﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Design;

namespace UtfprLibrary.Windows.Forms {
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(ResourceFinder), "Resources.VSD_UtfprLogWindow.png")]
    public partial class UtfprLogWindow : UtfprLogWindowBase {
        #region Base

        public override void ShowInfo(string title, string message) {
            addMessage(title, Color.Blue, false);
            appendText(message, Color.Gray, FontStyle.Regular);
        }

        public override void ShowResult(string title, string message) {
            addMessage(title, Color.Blue, false);
            appendText(message, Color.Black, FontStyle.Bold);
        }

        public override void ShowError(string title, string message) {
            addMessage(title, Color.Blue, true);
            appendText(message, Color.Red, FontStyle.Regular);
        }

        #endregion

        public UtfprLogWindow() {
            InitializeComponent();
        }
        
        #region Properties

        private int verticalScrollPosition = 0;
        private RichTextBox currentRichTextBox = null;

        private Image _imageFail = null;
        [Category("Layout")]
        public Image ImageFail {
            get {
                if (_imageFail == null) {
                    _imageFail = imageList.Images[1];
                }

                return _imageFail; 
            }
            set { _imageFail = value; }
        }

        private Image _imageOK = null;// (Image)Resources.ResourceManager.GetObject("green.Image");
        [Category("Layout")]
        public Image ImageOK {
            get {
                if (_imageOK == null) {
                    _imageOK = imageList.Images[0];
                }

                return _imageOK;             
            }
            set { _imageOK = value; }
        }

        #endregion

        #region EventHandlers

        private void UtfprLogWindow_Load(object sender, EventArgs e) {
            var form = FindForm();
            new MinimizeEventIntercept(form.Handle, this);

            form.Paint += new PaintEventHandler(form_Paint);
        }

        private void rtx_ContentsResized(object sender, ContentsResizedEventArgs e) {
            ((RichTextBox)sender).Height = e.NewRectangle.Height;
        }

        private void rtx_MouseEnter(object sender, EventArgs e) {
            tlpItems.Focus();
        }
        
        /// <summary>
        /// Corrige o Scrool da tela de Log
        /// </summary>
        private void form_Paint(object sender, PaintEventArgs e) {
            this.removeHorizontalScroll();
            this.refreshVerticalScroll();
        }

        #endregion

        #region Override
                
        /// <summary>
        /// Solves flickering
        /// </summary>
        protected override CreateParams CreateParams {
            get {
                CreateParams CP = base.CreateParams;
                CP.ExStyle = CP.ExStyle | 0x02000000;
                return CP;
            }
        }

        #endregion

        #region Private Methods

        private void clearMessages() {
            tlpItems.Controls.Clear();
            tlpItems.RowCount = 0;
        }
        
        private void saveVerticalScrollPosition() {
            verticalScrollPosition = tlpItems.VerticalScroll.Value;
        }

        private void removeHorizontalScroll() {
            tlpItems.Padding = new Padding(0, 0, SystemInformation.VerticalScrollBarWidth, 0);
        }

        private void refreshVerticalScroll() {
            tlpItems.AutoScroll = false;
            tlpItems.AutoScroll = true;

            //é preciso setar duas vezes mesmo, isso é um bug do Winforms
            tlpItems.VerticalScroll.Value = verticalScrollPosition;
            tlpItems.VerticalScroll.Value = verticalScrollPosition;
        }

        /// <summary>
        /// Adiciona uma mensagem ao controle
        /// </summary>
        /// <param name="message">A mensagem a ser adicionada</param>
        /// <param name="isErrorMessage">Verifica se é uma mensagem de erro ou status</param>
        private void addMessage(string message, Color fontColor, bool isErrorMessage) {
            //limpa se tiver mais que 500 linhas
            if (tlpItems.Controls.Count > 500) {
                clearMessages();
            }

            currentRichTextBox = new RichTextBox();
            currentRichTextBox.Anchor = ((AnchorStyles)((((AnchorStyles.Top | AnchorStyles.Bottom) | AnchorStyles.Left) | AnchorStyles.Right)));
            currentRichTextBox.BackColor = SystemColors.Window;
            currentRichTextBox.BorderStyle = BorderStyle.None;
            currentRichTextBox.Margin = new Padding(0);

            var currentDateTime = " " + DateTime.Now.ToString() + "  ";

            int nextSelectionStart = 0;

            ////adiciono a data atual como bold preto
            nextSelectionStart = currentRichTextBox.TextLength;
            currentRichTextBox.AppendText(currentDateTime);
            currentRichTextBox.SelectionStart = nextSelectionStart;
            currentRichTextBox.SelectionLength = currentDateTime.Length;
            currentRichTextBox.SelectionFont = new Font(currentRichTextBox.Font, FontStyle.Bold);
            currentRichTextBox.SelectionColor = Color.Black;
            ////==========================

            ////adiciono a mensagem como regular
            nextSelectionStart = currentRichTextBox.TextLength;
            currentRichTextBox.AppendText(message + " ");
            currentRichTextBox.SelectionStart = nextSelectionStart;
            currentRichTextBox.SelectionLength = message.Length;
            currentRichTextBox.SelectionFont = new Font(currentRichTextBox.Font, FontStyle.Regular);
            currentRichTextBox.SelectionColor = fontColor;
            ////==========================

            currentRichTextBox.ContentsResized += new ContentsResizedEventHandler(rtx_ContentsResized);
            currentRichTextBox.MouseEnter += new EventHandler(rtx_MouseEnter);

            var pbx = new PictureBox();

            if (isErrorMessage) {
                pbx.Image = ImageFail;
            } else {
                pbx.Image = ImageOK;
            }

            pbx.Margin = new Padding(0);
            pbx.Size = new Size(16, 16);
            pbx.SizeMode = PictureBoxSizeMode.AutoSize;
            pbx.TabStop = false;

            tlpItems.Controls.Add(pbx, 0, tlpItems.RowCount);
            tlpItems.Controls.Add(currentRichTextBox, 1, tlpItems.RowCount);

            tlpItems.RowCount++;
            tlpItems.RowStyles.Add(new RowStyle(SizeType.AutoSize));

            removeHorizontalScroll();
            refreshVerticalScroll();
        }

        /// <summary>
        /// Anexa um texto a mensagem atual (ultima mensagem inserida através do método AddMessage(string message, bool isErrorMessage)
        /// </summary>
        private void appendText(string message, Color fontColor, FontStyle fontStyle) {
            if (currentRichTextBox != null) {
                int nextSelectionStart = currentRichTextBox.TextLength;

                //currentRichTextBox.AppendText(" " + message);
                currentRichTextBox.AppendText(message);
                currentRichTextBox.SelectionStart = nextSelectionStart;
                currentRichTextBox.SelectionLength = message.Length;

                currentRichTextBox.SelectionFont = new Font(currentRichTextBox.Font, fontStyle);
                currentRichTextBox.SelectionColor = fontColor;
            }
        }

        /// <summary>
        /// Anexa um texto a mensagem atual (ultima mensagem inserida através do método AddMessage(string message, bool isErrorMessage)
        /// </summary>
        private void appendException(Exception ex) {
            appendText("Exceção disparada: " + ex.Message, Color.Red, FontStyle.Italic);
        }

        #endregion

        #region Captura o evento MINIMIZE, salvando a posição atual do SCROLL

        /// <summary>
        /// Captura o evento MINIMIZE, salvando a posição atual do SCROLL
        /// http://stackoverflow.com/questions/3481718/c-override-method-at-runtime
        /// </summary>
        private class MinimizeEventIntercept : NativeWindow {
            UtfprLogWindow utfprLogWindow = null;

            public MinimizeEventIntercept(IntPtr hWnd, UtfprLogWindow utfprLogWindow) {
                this.utfprLogWindow = utfprLogWindow;
                this.AssignHandle(hWnd);
            }

            protected override void WndProc(ref System.Windows.Forms.Message m) {
                const int WM_SYSCOMMAND = 0x112;
                const int SC_MINIMIZE = 0xF020;

                if (m.Msg == WM_SYSCOMMAND) {
                    if (m.WParam == (IntPtr)SC_MINIMIZE) {
                        this.utfprLogWindow.saveVerticalScrollPosition();
                    }
                }
                base.WndProc(ref m);
            }
        }

        #endregion
    }
}